package com.hy.example.shared.distribute.map;

import com.hy.example.shared.distribute.lock.DelegatingLock;
import com.hy.example.shared.distribute.lock.DistLock;
import com.hy.example.shared.distribute.lock.DistReadWriteLock;
import com.hy.example.shared.distribute.lock.DelegatingLock;
import com.hy.example.shared.distribute.lock.DelegatingReadWriteLock;
import com.hy.example.shared.distribute.lock.DistLock;
import com.hy.example.shared.distribute.lock.DistReadWriteLock;
import com.hy.example.shared.distribute.lock.DelegatingLock;
import com.hy.example.shared.distribute.lock.DistLock;
import com.hy.example.shared.distribute.lock.DistReadWriteLock;
import lombok.RequiredArgsConstructor;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * 委托实现/单实例优化 分布式Java Map
 *
 * @param <K> Map Key 类型
 * @param <V> Map Value 类型
 */
@RequiredArgsConstructor
public class StandaloneMap<K, V> implements DistMap<K, V> {
    private final Map<K, DistLock> distLocks = new ConcurrentHashMap<>();
    private final Map<K, DistReadWriteLock> distReadWriteLocks = new ConcurrentHashMap<>();
    
    private final ConcurrentMap<K, V> delegatingMap;

    @Override
    public DistLock getLock(K key) {
        return distLocks.computeIfAbsent(key,
                k -> new DelegatingLock(new ReentrantLock()));
    }

    @Override
    public DistReadWriteLock getReadWriteLock(K key) {
        return distReadWriteLocks.computeIfAbsent(key,
                k -> new DelegatingReadWriteLock(new ReentrantReadWriteLock()));
    }

    @Override
    public int size() {
        return delegatingMap.size();
    }

    @Override
    public boolean isEmpty() {
        return delegatingMap.isEmpty();
    }

    @Override
    public boolean containsKey(Object key) {
        return delegatingMap.containsKey(key);
    }

    @Override
    public boolean containsValue(Object value) {
        return delegatingMap.containsValue(value);
    }

    @Override
    public V get(Object key) {
        return delegatingMap.get(key);
    }

    @Override
    public V put(K key, V value) {
        return delegatingMap.put(key, value);
    }

    @Override
    public V remove(Object key) {
        return delegatingMap.remove(key);
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> m) {
        delegatingMap.putAll(m);
    }

    @Override
    public void clear() {
        delegatingMap.clear();
    }

    @Override
    public Set<K> keySet() {
        return delegatingMap.keySet();
    }

    @Override
    public Collection<V> values() {
        return delegatingMap.values();
    }

    @Override
    public Set<Entry<K, V>> entrySet() {
        return delegatingMap.entrySet();
    }

    @Override
    public V getOrDefault(Object key, V defaultValue) {
        return delegatingMap.getOrDefault(key, defaultValue);
    }

    @Override
    public void forEach(BiConsumer<? super K, ? super V> action) {
        delegatingMap.forEach(action);
    }

    @Override
    public V putIfAbsent(K key, V value) {
        return delegatingMap.putIfAbsent(key, value);
    }

    @Override
    public boolean remove(Object key, Object value) {
        return delegatingMap.remove(key, value);
    }

    @Override
    public boolean replace(K key, V oldValue, V newValue) {
        return delegatingMap.replace(key, oldValue, newValue);
    }

    @Override
    public V replace(K key, V value) {
        return delegatingMap.replace(key, value);
    }

    @Override
    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        delegatingMap.replaceAll(function);
    }

    @Override
    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
        return delegatingMap.computeIfAbsent(key, mappingFunction);
    }

    @Override
    public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        return delegatingMap.computeIfPresent(key, remappingFunction);
    }

    @Override
    public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        return delegatingMap.compute(key, remappingFunction);
    }

    @Override
    public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        return delegatingMap.merge(key, value, remappingFunction);
    }
}
